用 Electron 开发一个桌面 APP

编译:开源中国

https://www.oschina.net/translate/how-to-build-your-first-app-with-electron



你是否曾经想过可以用 HTML、CSS 和 JavaScript 这些前端技术来构建跨平台的桌面应用?


使用 Electron 就能做到。


本文带着你深入 Electron 的核心概念。


阅读本文后,你会知道如何使用 Electron、HTML 和 CSS 构建跨平台桌面应用。

在开始之前,你可以提前看看我们在本教程中要构建的应用。


Hear Me Type [译者注:本文的示例应用名为 Hear Me Type] 功能简单直接,应用中每个键都会播放特有的声音。比如我按下了 “A”,应用会播放字母 A 特有的声音。


该应用目前有两个版本可供下载: 本教程的源码 ,以及一个推荐给更有经验的 Electron 用户的 高级版本


因为我还在为改善应用以及添加一些新功能,所以代码会发生变化,请一定注意看看有哪些更新。


就此打住,我们现在开始学习 Electron 并用它来创建第一个应用!


什么是 Electron?


Electron 是一个基于 Chrominum 和 Node.js 的跨平台桌面应用框架。


在这个框架中很容易构建基于 HTML、CSS 和 JavaScript 技术的跨平台应用。构建出来的应用会很好地兼容 Mac、Windows 和 Linux 操作系统。


它还有其它一些特性:



如果你对 Electron 的功能感到满意,我们就继续深入,创建一个简单的 Electron 应用。


动手之前需要先安装  Node.js 。你还应该申请一个  GitHub  账户来保存和更新应用。虽然这个账户并不是必须的,但我非常建议你去申请一个。Github 是一个行业标准,学会使用 Github 非常重要。


我会在教程中使用 Github。


开始


准备好之后,打开系统终端窗口。


按照下面的介绍将 Electron Quick Start 这个 Git 库 克隆 到计算机上。


我们会基于 Electron Quick Start 来创建自己的软件。



完成上面的步骤之后,你会看到一个像浏览器窗口的应用打开。它确实是一个浏览器窗口!


这个窗口显示的样子在不同的操作系统上会有所不同。我选择使用 Windows 的经典样式。非常赞!



Quick-Start Electron 应用的主窗口


正如我之前所说,你可以在应用中使用 Chrome 开发者工具,这个工具的用法跟在浏览器中的开发者工具一样,再赞一个!


Electron 应用程序架构


我们来看看这个应用的源代码及其文件结构。可以使用你自己喜欢的编辑器或者 IDE 打开项目,我使用  Atom  …… 你猜到了 …… 它就是用 Electron 构建的![译者注:我比较喜欢  VSCode ,也是基于 Electron 构建的]



新应用的目录和文件结构。


我们有一个基本的文件结构:


electron-quick-start

- index.html
- main.js
- package.json
- render.js


文件结构类似于我们创建网页的结构。


我们有:



也许你对主进程和渲染进程存有疑问。它们到底是什么,用来干什么?


很高兴你有此疑问。注意了,如果你来自浏览器的 JavaScript 领域,这对你来说可能是一块新的领域!


什么是进程?


看到“进程”这个词的时候,想像一下操作系统级的进程。那是运行在系统中的计算机程序实例。


启动 Electron 应用之后,查看 Windows 的任务管理器或者 macOS 的活动监视器,就可以看到与这个应用相关的进程。



这些进程都是并行运行的,为每个进程分配的内存和资源相互隔离。


如果我想创建一个 for 循环在渲染进程中逐步处理一些事件。



这些改变只在渲染进程中有效,根本不会对主进行造成影响。“This is a for loop”消息只会出现在渲染模块中。


主进程


主进程控制着应用的生命周期。它内置了完整的 Node.js API,可以打开对话框,创建渲染进程,还可以处理其它其它与操作系统的交互操作,包括启动和退出应用。

按照惯例,这个进程写在名为 main.js 的文件中。不过你想使用其它名字也没有问题。


你可以在 package.json 文件中配置主进程文件的名称。


试验一下,打开 package.json 并将


“main”: “main.js”,


修改为


“main”: “mainTest.js”,


启动应用看看它是否仍然正常运行。


注意,主进程只有一个。


渲染进程


应用中的渲染进程是一个浏览器窗口。与主进程不同,可以存在多个独立的渲染进程。


因为渲染进程是各自独立的,如果其中一个崩溃了并不会影响到其它进程,这得益于 Chrominum 的多进程架构。


这些浏览器窗口就像演示网页一样,也可以被隐藏或自定义。


不过 Electron 内置了完整的 Node.js API,也就是说我们可以打开对话框或进行其它与操作系统的交互。


像这样考虑:



[来源: Kristian  Poslek ]


还有一个问题,它们能以某种方式联系起来吗?


这些进程都在独立运行,但他们仍然需要通信,因为它们负责不同的任务,这尤其需要通信。


为此,存在一个进程间的通信系统或者 IPC。你可以使用 IPC 在主进程和渲染进程间进行通信。对于这个知识点更深入一些的解释,请阅读 Christian Engvall 的 文章

上面说的都是开发 Electron 应用的基础知识。


现在回到我们的代码!


私有化


让我们给应用所 在的目录起一个合适的名称。


将目录名从 electron-quick-start 改为 hear-me-type-tutorial。


重新在编辑器或 IDE 中打开这个目录,我们打开 package.json 来进一步定制应用标识。


package.json 包含了至关重要的应用信息。这里定义应用的名称、版本、主文件、作者、许可协议等。


现在把作者改成自己的名称,自豪感油然而生。


找到 “author” 参数,然后将值改成自己的名称。它看起来像这样:


“author”: “Carol Pelu”,


我们还要改其它一些参数。在 package.json 中找到 name(名称) 和 description(说明)并修改它们:



帅呆了!现在应用有了新名称,还有简短而清晰的说明。


记住,你可以在终端运行 npm start 来运行应用,以观察所做的改变。


我们会继续在应用中添加一些期望的功能。我们想在按下每个键的时候播放不同的声音。


哦,有趣的功能!


没有功能的应用是什么?什么都不是……


现在我们要给它添加功能。


为了让应用响应输入,我们必须定义一个元素来捕捉事件,然后触发期望的动作。


为此,我们会创建一个具有特殊名称的若干 audio 元素,对应于按键。然后我们会使用一个 switch 语句来定位按下的键,播放与之关联的声音。


如果你现在觉得有点复杂,不要怕,我会指引你一步步进行。


下载这个 压缩包(https://neutrondev.com/wp-content/uploads/2017/05/sounds.zip?x77671) ,它包含了我们要使用的所有声音文件。很快就会用到!


我们会打开 index.html 文件,创建一个 <audio> 元素,在我们的应用中加入声音。

在 <body> 元素内部,创建一个 div 元素,将其 class 属性设置为 audio。


在刚刚创建的 div 元素,创建 <audio> 元素,将其 ID 命名为 “A”,source 属性设置为 “sounds/A.mp3”,preload 属性设置为 “auto”。


preload=”auto” 用于告诉应用在页面加载的时候就加载完整的声音文件。 index.html 是应用的主文件,所有声音都会在应用启动的时候加载。


下面是代码:



你的 index.html 应该就像这样。


现在 <audio> 指向一个未知的文件。我们要创建一个名为 soudes 的目录,并将所有声音文件解压到这个目录中。


非常好!现在唯一缺少的是 JavaScriopt 代码。


创建一个叫 functions.js 的新文件,并在 index.html 中通过 require 引用它,这样应用运行的时候才会执行 JS 代码。


在示例的 require(./renderer.js') 下载添加这样一行:


require('./functions.js')


之后项目看起来是这样的:



不错!一切就绪,下面是见证奇迹的时刻。


打开 functions.js 文件并将下面的代码添加到文件中。我稍后解释这段代码。



代码现在是这样:



打开 Bash 或者终端窗口,确保当前是在项目目录下,运行 npm start 来启动应用。

调整扬声器的音量并敲下按键。


#MindBlown



JS 代码非常简单明了。


我们使用了 document 对象上的 onkeydown 事件,在这里找到被访问的元素。记住,document 对象是应用的主窗口。


我们在在匿名函数中使用了 switch 语句,根据 Unicode 值来判断按键。


如果找到按键对应的 Unicode 值,就会播放相应的声音,否则抛出 “not found” 错误。这个错误要在控制台中去找。


多么愉快的过程!


你可能注意到了,我们的声音文件包含了 A-Z 和 0-9 这些键,把它们都用起来。

在 index.html 中为每个有对应声音文件的键都创建一个 <audio> 元素。


之后代码就像这样:



当然你可以用拷贝粘贴:



现在在 functions.js 中加点代码。


你可以在这个 网站 上查到字符码(charCode 或 keyCode)。


当然,也可以使用拷贝粘贴:


document.onkeydown = function(e) {

    switch (e.keyCode) {

        case 48:

            document.getElementById('0').play();

            break;

        case 49:

            document.getElementById('1').play();

            break;

        case 50:

            document.getElementById('2').play();

            break;

        case 51:

            document.getElementById('3').play();

            break;

        case 52:

            document.getElementById('4').play();

            break;

        case 53:

            document.getElementById('5').play();

            break;

        case 54:

            document.getElementById('6').play();

            break;

        case 55:

            document.getElementById('7').play();

            break;

        case 56:

            document.getElementById('8').play();

            break;

        case 57:

            document.getElementById('9').play();

            break;

        case 65:

            document.getElementById('A').play();

            break;

        case 66:

            document.getElementById('B').play();

            break;

        case 67:

            document.getElementById('C').play();

            break;

        case 68:

            document.getElementById('D').play();

            break;

        case 69:

            document.getElementById('E').play();

            break;

        case 70:

            document.getElementById('F').play();

            break;

        case 71:

            document.getElementById('G').play();

            break;

        case 72:

            document.getElementById('H').play();

            break;

        case 73:

            document.getElementById('I').play();

            break;

        case 74:

            document.getElementById('J').play();

            break;

        case 75:

            document.getElementById('K').play();

            break;

        case 76:

            document.getElementById('L').play();

            break;

        case 77:

            document.getElementById('M').play();

            break;

        case 78:

            document.getElementById('N').play();

            break;

        case 79:

            document.getElementById('O').play();

            break;

        case 80:

            document.getElementById('P').play();

            break;

        case 81:

            document.getElementById('Q').play();

            break;

        case 82:

            document.getElementById('R').play();

            break;

        case 83:

            document.getElementById('S').play();

            break;

        case 84:

            document.getElementById('T').play();

            break;

        case 85:

            document.getElementById('U').play();

            break;

        case 86:

            document.getElementById('V').play();

            break;

        case 87:

            document.getElementById('W').play();

            break;

        case 88:

            document.getElementById('X').play();

            break;

        case 89:

            document.getElementById('Y').play();

            break;

        case 90:

            document.getElementById('Z').play();

            break;

        default:

            console.log("Key is not found!");    

    }

};


大功告成!


应用的主要功能已经完成了,但仍然还有些工作要做!


完善!


应用程序的功能已经完成,但它尚不完善。


比如,可以在 index.html 中修应用的标题和主窗口的内容。


此外,这个应用没有设计炫丽的色彩,也没有使用漂亮的图片。


充分发挥你的想像,找出改进应用设计的方法。


代码也不完美,我们有很多相同的代码需要优化以减少代码行数,至少看起来不那么难受。


重复代码真不是好做法!


测试!就是测试!


好的软件需要通过测试。


我建议你先按键看看,会发生什么事。


最好的情况是你会听到每个键对应的声音。但如果你快速的按下多个键的时候会发生什么呢?如果按下了非预期的键,比如 Home 和 NumLock,又会发生什么呢?


如果你最小化程序再尝试着按钮会怎样?能听到声音吗?如果没有选择应用程序窗口,按下键盘时,还会听到声音吗?


答案是否定的。


Electron 的架构决定了其行为。它允许你可以像 C# 语言那样使用所有按键,但你不能注册个性化的按键。这已经超出了 Electron 应用的使用范围。


一行行的执行代码,并深度中断它,看看会发生什么,Electron 会抛出什么样的错误。这一练习能帮助你更好地进行调试。如果你知道应用的缺陷,那么你就知道该如何去修复,让应用变得更好。


我故意在 functions.js 文件中使用了一个废弃的 JavaScript 事件,你能发现吗?


如果你找到了,我希望你能在不改变应用程序功能的情况下替换它。


使用废弃的代码很不好,这可能会导致严重错误,你甚至可能意识不到这些错误的存在。关注语言的最新文件,了解可能发生的变化,始终了解最新状态。


结尾


非常感谢你的阅读。


你现在已经有创建一个简单的跨平台 Electron 应用的能力了。


如果你想更深入的了解 Electron,了解我对  Hear Me Type  的改进,还有我 GitHub 上的资料。


欢迎你来 clo ne, fork, star 我所有公开的项目,或者提交贡献。